import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;  //所有导入的包都是反射底下的
import java.lang.reflect.Method;


/*反射的几个重要的类：Constructor类--》类的构造方法
*                  Field类 --》 类的私有成员变量
*                  Method类 --》  类的方法
*                  class类 --》   对类进行反射*/

//在后面学的框架中有些东西会用到反射

public class ReflectClassDemo {
    public static void reflectNewInstance() {//所以在类外就创建了一个学生对象，没有new一个student
        try {
            Class<?> c1 = Class.forName("Student");
            //在类外拿到这个类的构造方法   它的返回值是一个T类型，默认就是object类型，可以强转为学生类
            /*它现在拿的是不带参数的构造方法，所以打印的时候就是默认初始化的name和age*/
            Student student = (Student)c1.newInstance();
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    public static void reflectPrivateConstrutcor() {
        try {
            Class<?> c1 = Class.forName("Student");
            //在类外拿到这个类的构造方法   它的返回值是一个T类型，默认就是object类型，可以强转为学生类
            /*它现在拿的是不带参数的构造方法，所以打印的时候就是默认初始化的name和age*/
            Constructor<?> constructor = c1.getDeclaredConstructor(String.class,int.class);//获取所有的构造方法
            constructor.setAccessible(true);//它的意思就是你此时调用的构造方法是私有的，程序员要确认一下，确实要调用它吗，这个必须要写
            Student student = (Student) constructor.newInstance("jiaoao",23);//constructor是所有的构造方法，然后newInstance是调用构造方法
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    public static void refectPrivateField() {
        try {
            Class<?> c1 = Class.forName("Student");
            Field field = c1.getDeclaredField("name");
            field.setAccessible(true);//声明一下
            Student student = (Student)c1.newInstance();
            field.set(student,"骄傲");//改变学生类中的私有成员变量
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    public static void reflectPrivateMethod() {
        try {
            Class<?> c1 = Class.forName("Student");
            Method method = c1.getDeclaredMethod("function", String.class);
            method.setAccessible(true);
            Student student = new Student();
            method.invoke(student,"我是一个参数！");
            /*反射的缺点：效率不高，我调用一个类的私有方法，首先要反射这个类拿到这个Student类，然后
            拿到这个类中的这个私有方法，然后再确认调用，然后new一个对象，最后在类外调用这个类的私有方法进行传参
            相当于是我调用一个方法之前，需要调用很多个方法才能完成这个私有方法的反射，效率很低
            */
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        //reflectNewInstance();反射不带参数的构造方法
        //reflectPrivateConstrutcor();//此时就在类外拿到了student类中带两个参数的构造方法，哪怕这个构造方法是私有的
        //refectPrivateField();//反射私有成员变量
        reflectPrivateMethod();//反射私有方法
    }
}
